<?php
/*
 * Multi cURL Class
 * Written by Howard Liu <howard@ixnet.work>
 * Licensed under MIT
 */

namespace IXNetwork\Lib\Tool;

class MultiCURL
{
    /**
     * Generate a cURL handle
     *
     * @param string $url
     * @param array $params
     * @return mixed
     */
    public static function createHandle($url, $params = [])
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt_array($ch, $params);
        return $ch;
    }

    /**
     * Create and execute multi cURL requests
     *
     * @param array $urls
     * @param int $maxThread
     * @param array $params
     * @return array
     */
    public static function exec($urls, $maxThread = 10, $params = [])
    {
        $maxThread = ($maxThread <= sizeof($urls)) ? $maxThread : sizeof($urls);
        $mh = curl_multi_init();
        $chs = [];
        for ($i=0; $i < sizeof($urls); $i++) {
            $chs[$i] = self::createHandle($urls[$i], $params);
        }

        // Add init handles
        for ($i = 0; $i < $maxThread; $i++) {
            curl_multi_add_handle($mh, $chs[$i]);
        }

        // Execute the stack
        $info = [];
        do {
            do {
                $cme = curl_multi_exec($mh, $active);
            } while ($cme == CURLM_CALL_MULTI_PERFORM);

            if ($cme != CURLM_OK) {
                break;
            }

            while ($done = curl_multi_info_read($mh)) {
                // Receiving information, error and content
                $handleIndexNo = array_search($done['handle'], $chs);
                if ($error = curl_error($done['handle'])) {
                    $result = [
                        'result' => 'error',
                        'error'  => $error,
                        'errorNo'=> curl_errno($done['handle'])
                    ];
                } else {
                    $result = [ 'result' => 'OK' ];
                }
                $result['info'] = curl_getinfo($done['handle']);
                $result['content'] = curl_multi_getcontent($done['handle']);
                $info[$handleIndexNo] = $result;

                if ($i < sizeof($chs)) {
                    curl_multi_add_handle($mh, $chs[$i]);
                    $i++;
                }

                // Remove the handle from the stack
                curl_multi_remove_handle($mh, $done['handle']);
            }

            if ($active) {
                curl_multi_select($mh, $maxThread);
            }
        } while ($active);

        curl_multi_close($mh);
        return $info;
    }
}
